package copyengine.utils {
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.geom.Matrix;
    import flash.geom.Rectangle;

    public class ImageUtils {
        private static const IDEAL_RESIZE_PERCENT:Number = .5;

        private static const MAX_WIDTH:uint = 2048;

        private static const MAX_HEIGHT:uint = 2048;

        public static function resizeImage(source:BitmapData, width:uint, height:uint):BitmapData {
            var bitmapData:BitmapData;
            var crop:Boolean = false;
            var fill:Boolean = true;
            var constrain:Boolean = false;

            // Find the scale to reach the final size
            var scaleX:Number = width / source.width;
            var scaleY:Number = height / source.height;

            if (width == 0 && height == 0) {
                scaleX = scaleY = 1;
                width = source.width;
                height = source.height;
            } else if (width == 0) {
                scaleX = scaleY;
                width = scaleX * source.width;
            } else if (height == 0) {
                scaleY = scaleX;
                height = scaleY * source.height;
            }

            if (crop) {
                if (scaleX < scaleY) scaleX = scaleY;
                else scaleY = scaleX;
            } else if (constrain) {
                if (scaleX > scaleY) scaleX = scaleY;
                else scaleY = scaleX;
            }

            var originalWidth:uint = source.width;
            var originalHeight:uint = source.height;
            var originalX:int = 0;
            var originalY:int = 0;
            var finalWidth:uint = Math.round(source.width * scaleX);
            var finalHeight:uint = Math.round(source.height * scaleY);

            if (fill) {
                originalWidth = Math.round(width / scaleX);
                originalHeight = Math.round(height / scaleY);
                originalX = Math.round((originalWidth - source.width) / 2);
                originalY = Math.round((originalHeight - source.height) / 2);
                finalWidth = width;
                finalHeight = height;
            }

            if (scaleX >= 1 && scaleY >= 1) {
                try {
                    bitmapData = new BitmapData(finalWidth, finalHeight, true, 0);
                } catch (error:ArgumentError) {
                    error.message += " Invalid width and height: " + finalWidth + "x" + finalHeight + ".";
                    throw error;
                }

                bitmapData.draw(source, new Matrix(scaleX, 0, 0, scaleY, originalX * scaleX, originalY * scaleY), null, null, null, true);
                return bitmapData;
            }

            // scale infoTree by the IDEAL for best quality
            var nextScaleX:Number = scaleX;
            var nextScaleY:Number = scaleY;
            while (nextScaleX < 1) nextScaleX /= IDEAL_RESIZE_PERCENT;
            while (nextScaleY < 1) nextScaleY /= IDEAL_RESIZE_PERCENT;

            if (scaleX < IDEAL_RESIZE_PERCENT) nextScaleX *= IDEAL_RESIZE_PERCENT;
            if (scaleY < IDEAL_RESIZE_PERCENT) nextScaleY *= IDEAL_RESIZE_PERCENT;

            bitmapData = new BitmapData(Math.round(originalWidth * nextScaleX), Math.round(originalHeight * nextScaleY), true, 0);
            bitmapData.draw(source, new Matrix(nextScaleX, 0, 0, nextScaleY, originalX * nextScaleX, originalY * nextScaleY), null, null, null, true);

            nextScaleX *= IDEAL_RESIZE_PERCENT;
            nextScaleY *= IDEAL_RESIZE_PERCENT;

            while (nextScaleX >= scaleX || nextScaleY >= scaleY) {
                var actualScaleX:Number = nextScaleX >= scaleX ? IDEAL_RESIZE_PERCENT : 1;
                var actualScaleY:Number = nextScaleY >= scaleY ? IDEAL_RESIZE_PERCENT : 1;
                var temp:BitmapData = new BitmapData(Math.round(bitmapData.width * actualScaleX), Math.round(bitmapData.height * actualScaleY), true, 0);
                temp.draw(bitmapData, new Matrix(actualScaleX, 0, 0, actualScaleY), null, null, null, true);
                bitmapData.dispose();
                nextScaleX *= IDEAL_RESIZE_PERCENT;
                nextScaleY *= IDEAL_RESIZE_PERCENT;
                bitmapData = temp;
            }

            return bitmapData;
        }

        private static var emptyBitmapData:BitmapData = new BitmapData(1, 1, true, 0);

        public static function cacheDisplayObjectToBitmapData(_target:DisplayObject, scale:Number = 1):BitmapData {
            var targetNormalScaleX:Number = _target.scaleX;
            var targetNormalScaleY:Number = _target.scaleY;

            emptyBitmapData.dispose();
            _target.scaleX = _target.scaleY = scale;
            var bounds:Rectangle = _target.getBounds(_target);
            var bitmapData:BitmapData;

            //need to convert the number to int , beacuse use number to cache the object will shake
            var offsetX:int = Math.ceil(bounds.x * _target.scaleX);
            var offsetY:int = Math.ceil(bounds.y * _target.scaleY);

            if (bounds.width == 0 || bounds.height == 0) {
                bitmapData = emptyBitmapData;
            }
            else {
                bitmapData = new BitmapData(Math.ceil(_target.width), Math.ceil(_target.height), true, 0xFFFFFF);
                bitmapData.draw(_target, new Matrix(_target.scaleX, 0, 0, _target.scaleY, -offsetX, -offsetY));
            }

            _target.scaleX = targetNormalScaleX;
            _target.scaleY = targetNormalScaleY;
            //var bitmap:Bitmap = new Bitmap(bitmapData);
            //bitmap.x = offsetX;
            //bitmap.y = offsetY;
            return bitmapData;
        }
    }
}
